/**
 * 内存管理系统所需数据结构的定义。
 */

#ifndef _AHAMOLETT_MM_TYPES_H_
#define _AHAMOLETT_MM_TYPES_H_

#include <stdatomic.h>
#include <cds/cds_types.h>

/// 包含一些暂时不方便在用户态中实现的功能，在实际移植的时候需要进行替换。
#include "../stubs.h"


#define PAGE_MAX_ORDER  11  /// 伙伴系统中最大内存页的order加一


/* 提前声明一些结构体。 */
struct page_struct;
struct zone_struct;
struct pglist_struct;

struct kmem_cache;


/* 描述物理页的结构体。 */
struct page_struct {
    /* 内存页的基本信息 */
    struct zone_struct *zone;   /// 内存页所属的内存区域。
    unsigned long physical; /// 当前页对应的物理地址。
    unsigned long flags;    /// 按位标志内存页的属性。
    atomic_long __ref_count;    /// 被引用次数的计数。
    atomic_long __map_count;    /// 被映射入页表的次数。
    
    /* 复合页的尾页，用于指向首页。 */
    union {
        struct {
            unsigned long order;    /// 对于复合页的头页，用于存放复合页大小的阶数。
            struct list_head lru;   /// 连接到lru链表或伙伴系统空闲链表的链表头。
        };
        struct page_struct *header_page;    /// 对于复合页的尾页，用于指向首页。
    };

    /* 根据不同类型的内存页起到不同的作用。 */
    union {
        
        /* SLAB分配器相关的信息。 */
        struct {
            struct kmem_cache *slab_cache;  /// 指向所在的 slab 描述符。
            void *free_list;    /// 指向当期 slab 对象的空闲链表。
            void *first_object; /// 指向当前 slab 对象内第一个 object 的地址。
            int free_object_entry;  /// 空闲链表中第一个空闲的 object 的编号。
            int free_objs;  /// 当前 slab 对象中总共的空闲 object 数量。
        };

        /* 反向映射相关信息。 */
        /// 待实现。

        /* LRU相关的信息。 */
        /// 待实现

        /* 文件映射相关的信息。 */
        /// 待实现。
    };
};


/* 伙伴系统中用于储存空闲内存页的链表结构体。 */
struct free_area {
    atomic_long free_count; /// 记录链表中空闲页的数量。
    struct list_head free_list; /// 存放空闲页的链表。 
};

/* LRU链表相关的结构体。 */
struct lruvec {
    struct list_head lru_list;  /// LRU链表本体。
};

/* 描述内存区域的结构体。 */
struct zone_struct {
    /* 内存区域基本的信息。 */
    /// 如果当前内存区域属于某个NUMA节点，指向其独享的 pglist 结构体。如果没有单独属于某个
    /// NUMA节点，则指向NULL。
    struct pglist_struct *global_info; 
    unsigned long zone_start_pfn;   /// 内存区域起始的页帧号。
    unsigned long owned_pages;  /// 内存区域内内存页的总数量。

    /* 伙伴系统相关的结构体 */
    unsigned long managed_pages;    /// 实际被伙伴系统管理的页数量。
    struct free_area free_area[PAGE_MAX_ORDER]; /// 伙伴系统储存空闲内存页的链表。

    /* LRU链表 */
    struct lruvec   lruvec; /// lru链表。

    /* 内存区域结构体的自旋锁。 */
    struct spinlock_t   lock;
};


/* 储存全局内存信息的结构体。 */
struct pglist_struct {
    /* 内存页相关的索引。 */
    unsigned long start_pfn;    /// 整个内存的起始页帧号。
    unsigned long spanned_pages;    /// 内存页结构体数组的大小。
    unsigned long owned_pages;    /// 属于当前 pglist 所在NUMA节点的内存页数量。
    unsigned long valid_pages;  /// 范围内有效内存页的数量。
    unsigned long node_num; /// 如果有多个NUMA节点，接该变量存放当前的节点号。

    /* 内存区域相关信息。 */
    unsigned long zones_count;  /// 当前所有的内存区域结构体数量。
    struct zone_struct **zones; /// 按照当前节点对内存区域优先级存放的内存区域结构体数组。

    /* 全局内存信息结构体的自旋锁。 */
    struct spinlock_t   lock;
};


#endif
